home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / fish / 001-100 / 001-025 / 014 / dex / dex1.c < prev    next >
C/C++ Source or Header  |  1995-03-17  |  13KB  |  540 lines

  1. /************************************************************************
  2.  *                                    *
  3.  *            Copyright (c) 1982, Fred Fish            *
  4.  *                All Rights Reserved                *
  5.  *                                    *
  6.  *    This software and/or documentation is released for public    *
  7.  *    distribution for personal, non-commercial use only.        *
  8.  *    Limited rights to use, modify, and redistribute are hereby    *
  9.  *    granted for non-commercial purposes, provided that all        *
  10.  *    copyright notices remain intact and all changes are clearly    *
  11.  *    documented.  The author makes no warranty of any kind with    *
  12.  *    respect to this product and explicitly disclaims any implied    *
  13.  *    warranties of merchantability or fitness for any particular    *
  14.  *    purpose.                            *
  15.  *                                    *
  16.  ************************************************************************
  17.  */
  18.  
  19.  
  20. /*
  21.  *  FILE
  22.  *
  23.  *    dex1.c   dynamic reconfiguration functions
  24.  *
  25.  *  KEY WORDS
  26.  *
  27.  *    dex files
  28.  *    dex
  29.  *
  30.  *  DESCRIPTION
  31.  *
  32.  *    This file contains functions for doing dynamic
  33.  *    reconfiguration.  DEX automatically searches
  34.  *    a directory for a reconfiguration file the first
  35.  *    time any file in that directory is processed.
  36.  *    The default reconfiguration file is ".dexrc" but
  37.  *    can be changed to any desired file via a command
  38.  *    line switch.
  39.  *
  40.  *  FUNCTIONS
  41.  *
  42.  *    make_entry   make an entry in the name table
  43.  *    reconfig     do dynamic reconfiguration
  44.  *    rc_name      build reconfiguration name
  45.  *    do_reconfig  process open reconfiguration file
  46.  *    do_flags     process reconfiguration ".flags" line
  47.  *    file_out     process reconfiguration ".output" line
  48.  *
  49.  *  AUTHOR
  50.  *
  51.  *    Fred Fish
  52.  *
  53.  */
  54.  
  55. #include <stdio.h>
  56. #include "hashtbl.h"
  57. #include "dex.h"
  58.  
  59. extern int debug;            /* Global debug flag */
  60. extern int vflag;            /* Global verbose flag */
  61. extern char *get_memory ();
  62.  
  63. static struct flgwrd {            /* Reconfiguration flags */
  64.     char *word;                /* String form of flag */
  65.     int flag;                /* Token form of flag */
  66. };
  67.  
  68. static struct flgwrd flgwrds[] = {    /* Flags recognized */
  69.     "PROCESS", PROCESS,
  70.     "EMITTEXT", EMITTEXT,
  71.     "EMITBOX", EMITBOX,
  72.     "EMITFILL", EMITFILL,
  73.     "EMITUL", EMITUL,
  74.     "EMITBP", EMITBP,
  75.     "REGION", REGION,
  76.     NULL, NULL                /* Marks end of flags list */
  77. };
  78.  
  79. /*
  80.  *  FUNCTION
  81.  *
  82.  *    make_entry   make an entry in table with specified name
  83.  *
  84.  *  KEY WORDS
  85.  *
  86.  *    hash table insertion
  87.  *
  88.  *  SYNOPSIS
  89.  *
  90.  *    struct tbl_data *make_entry(name)
  91.  *    char *name;
  92.  *
  93.  *  DESCRIPTION
  94.  *
  95.  *    Make_entry allocates memory for a table entry, initializes
  96.  *    it's name field, and then adds it to the hash table.
  97.  *    Each entry name is actually the string which is recognized
  98.  *    as starting a new documentation section, such as
  99.  *    "FUNCTION" or "DESCRIPTION".
  100.  *
  101.  *    Note that make_entry allocates fresh memory for the name
  102.  *    string, and copies the name there.  This insures that the
  103.  *    characters comprising the entry's name do not vanish
  104.  *    when somebody's stack is popped.
  105.  *
  106.  */
  107.  
  108. /*
  109.  *  PSEUDO CODE
  110.  *
  111.  *    Begin make_entry
  112.  *        Initialize entry pointer to NULL.
  113.  *        If name pointer is not invalid then
  114.  *            Get memory for the entry name.
  115.  *            If memory was allocated then
  116.  *            Copy the name to the fresh memory.
  117.  *            Get memory for the table data structure.
  118.  *            If memory was allocated then
  119.  *                Remember the name of the entry.
  120.  *                Add entry to table, getting pointer.
  121.  *            End if
  122.  *            End if
  123.  *        End if
  124.  *        Return table entry pointer.
  125.  *    End make_entry
  126.  *
  127.  */
  128.  
  129. static struct tbl_data *make_entry(name)
  130. char *name;
  131. {
  132.     struct tbl_data *temp, *tbl_add();
  133.     char *name_save;
  134.  
  135.     temp = NULL;
  136.     if (name != NULL) {
  137.         name_save = (char *) get_memory(strlen(name)+1);
  138.         if (name_save != NULL) {
  139.         strcpy(name_save,name);
  140.             temp = (struct tbl_data *) get_memory(sizeof(struct tbl_data));
  141.             if (temp != NULL) {
  142.             temp->name = name_save;
  143.             temp = tbl_add(temp);
  144.         if (debug) {printf("make_entry: added \"%s\"\n",temp->name);}
  145.         }
  146.         }
  147.     }
  148.     return(temp);
  149. }
  150.  
  151. /*
  152.  *  FUNCTION
  153.  *
  154.  *    reconfig   do dynamic reconfiguration if necessary
  155.  *
  156.  *  KEY WORDS
  157.  *
  158.  *    dynamic reconfiguration
  159.  *    reconfiguration routines
  160.  *
  161.  *  SYNOPSIS
  162.  *
  163.  *    reconfig(pfn,rcfn)
  164.  *    char *pfn;        (processed file name)
  165.  *    char *rcfn;        (rc file base name)
  166.  *
  167.  *  DESCRIPTION
  168.  *
  169.  *    Tests to see if a new reconfiguration file needs to
  170.  *    be processed and if so, opens it and calls routine
  171.  *    to actually do the reconfiguration.
  172.  *
  173.  */
  174.  
  175. /*
  176.  *  PSEUDO CODE
  177.  *
  178.  *    Begin reconfig
  179.  *        Build reconfiguration file name.
  180.  *        If name is not same as last used name then
  181.  *        If the reconfiguration file can be opened
  182.  *            Do the reconfiguration.
  183.  *            Remember name of reconfig file.
  184.  *            Close the reconfiguration file.
  185.  *        End if
  186.  *        End if
  187.  *    End reconfig
  188.  *
  189.  */
  190.  
  191. static char last_rcfile[MAXNAMESIZE];
  192.  
  193. reconfig(pfn,rcfn)
  194. char *pfn;
  195. char *rcfn;
  196. {
  197.     char buffer[MAXNAMESIZE];
  198.     FILE *rcfp, *fopen();
  199.  
  200.     rc_name(buffer,pfn,rcfn);
  201.     if (debug) {printf("reconfig: %s & %s => %s\n",pfn,rcfn,buffer);}
  202.     if (strcmp(buffer,last_rcfile) != 0) {
  203.     if ((rcfp = fopen(buffer,"r")) != NULL) {
  204.         if (vflag) {printf("dex: reconfiguring using \"%s\"\n",buffer);}
  205.         do_reconfig(rcfp);
  206.         strcpy(last_rcfile,buffer);
  207.         fclose(rcfp);
  208.     }
  209.     }
  210. }
  211.  
  212. /*
  213.  *  FUNCTION
  214.  *
  215.  *    rc_name   build the reconfiguration file name
  216.  *
  217.  *  KEY WORDS
  218.  *
  219.  *    dynamic reconfiguration
  220.  *    reconfiguration file
  221.  *
  222.  *  SYNOPSIS
  223.  *
  224.  *    static rc_name(out,pfn,rcfn)
  225.  *    char *out;            (output goes here)
  226.  *    char *pfn;            (processed file name)
  227.  *    char *rcfn;            (rc base file name)
  228.  *
  229.  *  DESCRIPTION
  230.  *
  231.  *    Builds the name used when an attempt is made to open
  232.  *    the reconfiguration file.  Assumes that if the specified
  233.  *    base reconfiguration file name does not contain a slash character
  234.  *    "/" then any prefix in the processed file name is to be
  235.  *    extracted and prepended to the specified base reconfiguration
  236.  *    file name.
  237.  *
  238.  *    For example, if the processed file name is "/usr/me/myfile"
  239.  *    and the base reconfiguration file name is
  240.  *    ".dexrc" then the name used to open the reconfiguration
  241.  *    file will be "/usr/me/.dexrc".
  242.  *    If however the base reconfiguration file name is
  243.  *    "/usr/me/newrc" then this name will simply be
  244.  *    returned unchanged
  245.  *
  246.  *    This seems to be the best way of handling reconfiguration
  247.  *    file names since if the full pathname is given then
  248.  *    only that file will be used regardless of where the
  249.  *    processed file is.  However a generic name may be
  250.  *    given (such as ".dexrc") in which case a search will
  251.  *    be made in the processed file's directory for a file
  252.  *    with that generic name.
  253.  *
  254.  */
  255.  
  256. /*
  257.  *  PSEUDO CODE
  258.  *
  259.  *    Begin rc_name
  260.  *        If the specified base rc file name contains "/"
  261.  *        Copy that name to output.
  262.  *        Else
  263.  *        Copy processed file name to work buffer.
  264.  *        If processed file name has no last "/" in it then
  265.  *            Simply copy base rc file name to output.
  266.  *        Else
  267.  *            Append base rc file name after last "/"
  268.  *            Copy concatenated names to output.
  269.  *        End if
  270.  *        End if
  271.  *    End rc_name
  272.  *
  273.  */
  274.  
  275. static rc_name(out,pfn,rcfn)
  276. char *out;            /* Pointer to output place */
  277. char *pfn;            /* Pointer to processed file name */
  278. char *rcfn;            /* Pointer to reconfig base file name */
  279. {
  280.     char buffer[MAXNAMESIZE];    /* Concatenation work buffer */
  281.     char *cp;            /* Work pointer for name build */
  282.     char *rindex();        /* Pointer to last occurrence of char */
  283.  
  284.     if (index(rcfn,'/') != NULL) {
  285.     strcpy(out,rcfn);
  286.     } else {
  287.     strcpy(buffer,pfn);
  288.     cp = rindex(buffer,'/');
  289.     if (cp == NULL) {
  290.         strcpy(out,rcfn);
  291.     } else {
  292.         strcpy(++cp,rcfn);
  293.         strcpy(out,buffer);
  294.     }
  295.     }
  296. }
  297.  
  298. /*
  299.  *  FUNCTION
  300.  *
  301.  *    do_reconfig   process open reconfiguration file
  302.  *
  303.  *  KEY WORDS
  304.  *
  305.  *    dynamic reconfiguration
  306.  *    reconfiguration routines
  307.  *
  308.  *  SYNOPSIS
  309.  *
  310.  *    do_reconfig(rcfp)
  311.  *    FILE *rcfp;
  312.  *
  313.  *  DESCRIPTION
  314.  *
  315.  *    Reads each record from the currently open reconfiguration
  316.  *    file, creating table entries if necessary, and adding
  317.  *    the reconfiguration information to the specified table
  318.  *    entries.
  319.  *
  320.  */
  321.  
  322. /*
  323.  *  PSEUDO CODE
  324.  *
  325.  *    Begin do_reconfig
  326.  *        While a record can be read from reconfiguration file
  327.  *        Zap the newline at the end.
  328.  *        Skip over any leading whitespace.
  329.  *        If the line has something useful then
  330.  *            Extract the option field.
  331.  *            Skip to start of next field.
  332.  *            If the option is to process flags then
  333.  *            Process all flags on the line.
  334.  *            Else if option is change output file
  335.  *            Change name of output file.
  336.  *            Else
  337.  *            Print warning message.
  338.  *            End if
  339.  *        End if
  340.  *        End while
  341.  *    End do_reconfig
  342.  *
  343.  */
  344.  
  345. do_reconfig(rcfp)
  346. FILE *rcfp;
  347. {
  348.     char buffer[256];
  349.     char string[128];
  350.     char *cp, *skpbt(), *xfield();
  351.  
  352.     while (fgets(buffer,sizeof(buffer),rcfp) != NULL) {
  353.     buffer[strlen(buffer)-1] = NULL;
  354.     cp = skpbt(buffer);
  355.     if (*cp != '#' && *cp != NULL && *cp != '\014') {
  356.         cp = xfield(string,cp);
  357.         cp = skpbt(cp);
  358.         if (strcmp(string,".flags") == 0) {
  359.         do_flags(cp);
  360.         } else if (strcmp(string,".output") == 0) {
  361.         file_out(cp);
  362.         } else {
  363.         fprintf(stdout,"dex: \"%s\" reconfiguration action?\n",string);
  364.         }
  365.     }
  366.     }
  367. }
  368.  
  369. /*
  370.  *  FUNCTION
  371.  *
  372.  *    do_flags   process flags for specified section
  373.  *
  374.  *  KEY WORDS
  375.  *
  376.  *    dynamic reconfiguration
  377.  *    flags
  378.  *
  379.  *  SYNOPSIS
  380.  *
  381.  *    do_flags(flags_line)
  382.  *    char *flags_line;
  383.  *
  384.  *  DESCRIPTION
  385.  *
  386.  *    Processes all flags for the current section, setting
  387.  *    or resetting those specified.  Flags not specified are
  388.  *    unchanged from the default (reset).
  389.  *
  390.  *    Flags may begin with an explicit action character
  391.  *    "-" or "+" for reset or set respectively.  The
  392.  *    default is to set the named flag.
  393.  *
  394.  */
  395.  
  396. /*
  397.  *  PSEUDO CODE
  398.  *
  399.  *    Begin do_flags
  400.  *        If the passed pointer is not invalid then
  401.  *        If there is a line to process then
  402.  *            Extract the name of the section.
  403.  *            Skip to next field (first flag).
  404.  *            If the section is not in table
  405.  *            Create a new table entry.
  406.  *            End if
  407.  *            While there is a flag field left
  408.  *            Extract flag field.
  409.  *            Skip to next field.
  410.  *            Init flag field pointer.
  411.  *            If explicit state character
  412.  *                Skip over it.
  413.  *            End if
  414.  *            For each entry in flags list
  415.  *                If entry matches flag string
  416.  *                If reset requested
  417.  *                    Reset flag.
  418.  *                Else
  419.  *                    Set flag.
  420.  *                End if
  421.  *                Break for loop
  422.  *                End if
  423.  *            End for
  424.  *            End while
  425.  *        End if
  426.  *        End if
  427.  *    End do_flags
  428.  *
  429.  */
  430.  
  431. static do_flags(cp)
  432. char *cp;
  433. {
  434.     char string[128];
  435.     char *xfield(), *skpbt();
  436.     struct tbl_data *rp, *make_entry(), *tbl_find();
  437.     struct flgwrd *flagp;
  438.     char *stp;
  439.  
  440.     if (cp != NULL) {
  441.         if (*cp != NULL) {
  442.         cp = xfield(string,cp);
  443.         cp = skpbt(cp);
  444.         if (debug) {printf("do_flags: region \"%s\"\n",string);}
  445.         if ((rp = tbl_find(string)) == NULL) {
  446.             rp = make_entry(string);
  447.         }
  448.         while (*cp != NULL) {
  449.             cp = xfield(string,cp);
  450.             cp = skpbt(cp);
  451.         if (debug) {printf("do_flags: got flag \"%s\"\n",string);}
  452.         stp = string;
  453.         if (*stp == '-' || *stp == '+') {
  454.             stp++;
  455.         }
  456.         for (flagp = flgwrds; flagp->word != NULL; flagp++) {
  457.             if (strcmp(flagp->word,stp) == 0) {
  458.             if (string[0] == '-') {
  459.                 rp->flags &= ~(flagp->flag);
  460.             } else {
  461.                 rp->flags |= flagp->flag;
  462.             }
  463.             break;
  464.             }
  465.         }
  466.         }
  467.     }
  468.     }
  469. }
  470.  
  471. /*
  472.  *  FUNCTION
  473.  *
  474.  *    file_out   reconfigure for new output file
  475.  *
  476.  *  KEY WORDS
  477.  *
  478.  *    dynamic reconfiguration
  479.  *    output file
  480.  *
  481.  *  SYNOPSIS
  482.  *
  483.  *    file_out(file_line)
  484.  *    char *file_line;
  485.  *
  486.  *  DESCRIPTION
  487.  *
  488.  *    Saves file name for output collection when specified
  489.  *    section is processed.  Note that the name must
  490.  *    be stuffed safely away in static memory since
  491.  *    it will go away when one of this routines ancestors
  492.  *    exits.
  493.  *
  494.  */
  495.  
  496. /*
  497.  *  PSEUDO CODE
  498.  *
  499.  *    Begin file_out
  500.  *        If passed pointer is not invalid then
  501.  *        If there is a line to use then
  502.  *            Extract name of section.
  503.  *            Skip to file name field.
  504.  *            If section is not in table
  505.  *            Create a new table entry.
  506.  *            End if
  507.  *            Extract name of file.
  508.  *            Allocate some static memory.
  509.  *            Save the name in static memory.
  510.  *            Remember where it is.
  511.  *        End if
  512.  *        End if
  513.  *    End file_out
  514.  *
  515.  */
  516.  
  517. file_out(cp)
  518. char *cp;
  519. {
  520.     char string[128];
  521.     char *xfield(), *skpbt();
  522.     struct tbl_data *rp, *make_entry(), *tbl_find();
  523.     char *file_save;
  524.  
  525.     if (cp != NULL) {
  526.         if (*cp != NULL) {
  527.         cp = xfield(string,cp);
  528.         cp = skpbt(cp);
  529.         if ((rp = tbl_find(string)) == NULL) {
  530.             rp = make_entry(string);
  531.         }
  532.             cp = xfield(string,cp);
  533.         file_save = (char *) get_memory(strlen(string)+1);
  534.         strcpy(file_save,string);
  535.         rp->out = file_save;
  536.         if (debug) {printf("file_out: out file \"%s\"\n",rp->out);}
  537.     }
  538.     }
  539. }
  540.